﻿//
// eCRAM, a monthly activity report web application
// Copyright (C) 2010  Aptea
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
//

using System;
using System.Collections.Generic;

namespace eCRAM.Tools
{
    public static class WorkingDay
    {
        
        public static List<bool> MonthWorkingDays(int year , int month)
        {
            var bolWorkingDay = new List<bool>();
            var arrDateFerie = GetHolidaysByYear(year);

            for (var i = 1; i <= DateTime.DaysInMonth(year, month); i++ )
            {
                var dateTime = new DateTime(year, month, i);
                // Dimanche ou jour férié
                var currentDay = !IsHoliday(dateTime, arrDateFerie);
                bolWorkingDay.Add(currentDay);
            }
            return bolWorkingDay;
        }

        private static bool IsHoliday(DateTime dateTime, Array arrDateFerie)
        {
            return dateTime.DayOfWeek == DayOfWeek.Sunday || dateTime.DayOfWeek == DayOfWeek.Saturday 
                || Array.BinarySearch(arrDateFerie, dateTime) >= 0;
        }

        public static bool IsHoliday(DateTime dateTime)
        {
            return dateTime.DayOfWeek == DayOfWeek.Sunday || dateTime.DayOfWeek == DayOfWeek.Saturday
                || Array.BinarySearch(GetHolidaysByYear(dateTime.Year), dateTime) >= 0;
        }

        private static Array GetHolidaysByYear(int year)
        {
            var arrDateFerie = new DateTime[11];
            // 01 Janvier
            arrDateFerie.SetValue(new DateTime(year, 1, 1), 0);
            // 01 Mai
            arrDateFerie.SetValue(new DateTime(year, 5, 1), 1);
            // 08 Mai
            arrDateFerie.SetValue(new DateTime(year, 5, 8), 2);
            // 14 Juillet
            arrDateFerie.SetValue(new DateTime(year, 7, 14), 3);
            // 15 Aout
            arrDateFerie.SetValue(new DateTime(year, 8, 15), 4);
            // 01 Novembre
            arrDateFerie.SetValue(new DateTime(year, 11, 1), 5);
            // 11 Novembre
            arrDateFerie.SetValue(new DateTime(year, 11, 11), 6);
            // Noël
            arrDateFerie.SetValue(new DateTime(year, 12, 25), 7);

          
            DateTime easterDay = GetEasterDay(year);
            arrDateFerie.SetValue( easterDay.AddDays(1),8);
            // Ascension
            arrDateFerie.SetValue( easterDay.AddDays(39),9);
            // Pentecote
            arrDateFerie.SetValue(easterDay.AddDays(50),10);
            return arrDateFerie;
        }

        private static DateTime GetEasterDay(int year)
        {
            // Calcul du jour de pâques (algorithme de Oudin (1940))
            //Calcul du nombre d'or - 1
            var intGoldNumber = (year % 19);
            // Année divisé par cent
            var intAnneeDiv100 = (year / 100);
            // intEpacte est = 23 - Epacte (modulo 30)
            var intEpacte =
                ((intAnneeDiv100 - intAnneeDiv100 / 4 - (8 * intAnneeDiv100 + 13) / 25 + (19 * intGoldNumber) + 15) % 30);
            //Le nombre de jours à partir du 21 mars pour atteindre la pleine lune Pascale
            var intDaysEquinoxeToMoonFull =
                (intEpacte - (intEpacte / 28) * (1 - (intEpacte / 28) * (29 / (intEpacte + 1)) * ((21 - intGoldNumber) / 11)));
            //Jour de la semaine pour la pleine lune Pascale (0=dimanche)
            var intWeekDayMoonFull =
                
                ((year + year / 4 + intDaysEquinoxeToMoonFull + 2 - intAnneeDiv100 +
                  intAnneeDiv100 / 4) % 7);
            // Nombre de jours du 21 mars jusqu'au dimanche de ou
            // avant la pleine lune Pascale (un nombre entre -6 et 28)
            var intDaysEquinoxeBeforeFullMoon = intDaysEquinoxeToMoonFull - intWeekDayMoonFull;
            // mois de pâques
            var intMonthPaques = (3 + (intDaysEquinoxeBeforeFullMoon + 40) / 44);
            // jour de pâques
            var intDayPaques = (intDaysEquinoxeBeforeFullMoon + 28 - 31 * (intMonthPaques / 4));
            // lundi de pâques
            return new DateTime(year, intMonthPaques, intDayPaques );
        }
    }
}
